package com.simen.downloader;

import android.os.Handler;
import android.os.Message;

import com.simen.downloader.exception.ToastException;
import com.simen.downloader.model.LocalFile;
import com.simen.downloader.util.AppLog;
import com.simen.downloader.util.Constants;
import com.simen.downloader.util.FileStorageUtils;
import com.simen.downloader.util.Utils;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 断点续传线程
 * Created by zhangming on 16/4/11.
 */
final class DownloadResumeThread extends ParentThread {
    private final Handler handler;
    private final String key;
    private final String logFilePath, filePath;
    private final ParcelFile storageFile;

    public DownloadResumeThread(DownloadEngine engine, DownloadInfor downloadInfor, Handler
            handler, ParcelFile storageFile) {
        super(engine, downloadInfor);
        this.handler = handler;
        this.key = downloadInfor.key;
        this.logFilePath = FileStorageUtils.getDefaultLogFilePath(downloadInfor.downloadOptions
                .fileDir, downloadInfor.key).getPath();
        this.filePath = FileStorageUtils.getDefaultFilePath(downloadInfor.downloadOptions
                .fileDir, downloadInfor.key).getPath();
        this.storageFile = storageFile;
    }


    @Override
    public void run() {
        if (waitIfPaused()) {
            return;
        }
        HttpURLConnection conn = null;
        DataOutputStream out = null;
        InputStream inputStream = null;
        RandomAccessFile randomFile = null;
        long createtime = 0, lasttime = 0;
        long writeLength = 0;
        int progress = 0;
        String finalUrl = storageFile.getFileRealUrl(), fileName = storageFile.getFileName();

        ReentrantLock lock = engine.getLockForUri(key);
        if (lock.isLocked()) {
            AppLog.dLog("the lock has been locked " + key);
        }

        lock.lock();
        try {
            writeLength = Utils.getReadFileLength(filePath);
            conn = Utils.openURLConnection(key, writeLength, storageFile.getTotal());
            conn.connect();
            int responseCode = conn.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_PARTIAL) {
                //第一次下载长度等于文件长度;断点下载时,长度为剩余要读取的长度
                long filelength = conn.getContentLength();
                if (filelength == -1) {
                    throw new ToastException("下载文件无效");
                }
                AppLog.dLog("剩余文件长度: " + filelength);

                checkThreadInterrupted();
                checkListenerRecycled();

                inputStream = conn.getInputStream();
                randomFile = new RandomAccessFile(filePath, "rw");
                final long remain = randomFile.length();
                randomFile.seek(remain);

                byte[] data = new byte[DownloadThread.BUFFER_SIZE];
                int read = 0;
                int newprogress = 0;
                long interval = System.currentTimeMillis();
                while ((read = inputStream.read(data, 0, DownloadThread.BUFFER_SIZE)) != -1) {
                    writeLength += read;
                    randomFile.write(data, 0, read);

                    progress = (int) (writeLength * 1.0 / filelength * 100);
                    if (downloadInfor == null) {
                        break;
                    }

                    ReentrantReadWriteLock.ReadLock readLock = downloadInfor.run.getReadLock();
                    readLock.lock();
                    boolean flag = downloadInfor.run.get();
                    readLock.unlock();
                    if (!flag) {
                        break;
                    }

                    if (progress % 5 == 0) {
                        checkThreadInterrupted();
                    }

                    if (downloadInfor.isCollected()) {
                        continue;
                    }

                    if (progress == 100 || (newprogress != progress && (System.currentTimeMillis()
                            - interval > Constants.PROGRESS_INTERVAL))) {
                        //刷新进度
                        newprogress = progress;
                        interval = System.currentTimeMillis();
                        Message.obtain(handler, 0, getStatus(key, finalUrl,
                                createtime, lasttime, writeLength, filelength, progress,
                                fileName, filePath)).sendToTarget();
                    }
                }
            } else {
                throw new ToastException("HTTP错误码：" + responseCode);
            }
        } catch (ToastException e) {
            catchExecption(handler, key, e);
        } catch (SocketTimeoutException e) {
            catchExecption(handler, key, e);
        } catch (Exception e) {
            catchExecption(handler, key, e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (Exception ee) {
            }
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception ee) {
            }

            try {
                if (randomFile != null) {
                    randomFile.close();

                    if (finalUrl != null) {
                        //保存文件下载信息
                        cachefile.setParamers(key, finalUrl, createtime, lasttime, writeLength,
                                storageFile.getTotal(), progress, fileName, filePath);
                        ParentThread.writeStatus(this.logFilePath, cachefile);
                    }
                }
            } catch (Exception e) {
            }

            if (conn != null) {
                conn.disconnect();
            }

            lock.unlock();
        }

        if (!isListenerRecycled()) {
            if (progress == 100) {//下载完成
                final LocalFile localFile = new LocalFile(filePath, finalUrl);
                handler.postDelayed(new DownloadService.MessageRunnable(getStatus(key, finalUrl, createtime,
                        lasttime, writeLength, storageFile.getTotal(), progress, fileName, filePath)) {
                    @Override
                    public void run() {
                        downloadInfor.loader.get().onProgress(key, 100);
                        downloadInfor.loader.get().onComplete(key, localFile);
                    }
                }, 0);
            } else { //任务停止运行
                handler.postDelayed(new DownloadService.MessageRunnable(getStatus(key,
                        finalUrl, createtime, lasttime, writeLength, storageFile.getTotal(),
                        progress, fileName, filePath)) {
                    @Override
                    public void run() {
                        downloadInfor.loader.get().onPause(key);
                    }
                }, 0);
            }
        }
    }

//    /**
//     * 获取下载进度信息
//     *
//     * @param logfilepath  下载日志存储文件路径
//     * @param readfilepath 实际下载文件路径
//     * @return 返回已存储的有效进度值
//     */
//    private long getReadedLength(String logfilepath, String readfilepath) {
//        File file = new File(readfilepath);
//        if (!file.exists() || !file.isFile()) {
//            return 0;
//        }
//        ObjectInputStream objectInputStream = null;
//        try {
//            objectInputStream = new ObjectInputStream(new FileInputStream(logfilepath));
//            StorageFile fileWriter = (StorageFile) objectInputStream.readObject();
//            if (fileWriter != null) {
//                if (fileWriter.getCurrent() >= file.length()) {
//                    //返回有效下载长度
//                    return file.length();
//                }
//            }
//        } catch (NotSerializableException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        } catch (ClassNotFoundException e) {
//            e.printStackTrace();
//        } finally {
//            try {
//                if (objectInputStream != null) {
//                    objectInputStream.close();
//                }
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//        return 0;
//    }
}
